/**
 * @class   wosh::building::BuildingObject
 * @brief   Base interface of building abstraction (floors, rooms, applicances)
 *          defined in wosh::building namespace.
 *          The class implements common methods, it is very similar to class
 *          wosh::BundleGeneric
 *
 * @see     wosh::services::BuildingManagerBundle
 ****************************************************************************
 * @version $Id: BuildingObject.h 2863 2010-08-07 04:28:58Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Building_BuildingObject_H__
 #define __WOSH_Building_BuildingObject_H__

 #include <core/Object.h>
 #include <core/Bus.h>
 #include <core/InterfacesProvider.h>
 #include <core/MethodsProvider.h>
 #include <core/PropertiesProvider.h>
 #include <core/Containers.h>
 #include <core/Method.h>
 #include <core/Request.h>
 #include <core/Fact.h>
 #include <core/BusConnector.h>
 #include <core/LogContext.h>
 #include <core/Device.h>

 #include <framework/building/BuildingGeometry.h>


namespace wosh {
 template <class T> class DataFieldCollector;
 namespace services {
  class BuildingManagerBundle;
 }
 namespace building {

 #define _BuildingObject_KEY_State				"State"
 #define _BuildingObject_KEY_StateTs			"StateTs"

 #define _BuildingObject_KEY_Position			"Position"
 #define _BuildingObject_KEY_Geometry			"Geometry"

 #define _BuildingObject_KEY_PositionGlobal		"PositionGlobal"
 #define _BuildingObject_KEY_Location			"Location"

 #define _BuildingObject_KEY_AlwaysRaiseEvents	"AlwaysRaiseEvents"

 #define _BuildingObject_EVENT_StateChanged		"StateChanged"

 #define _BuildingObject_METHOD_GetGeometry		"geometry_get"
 #define _BuildingObject_METHOD_force_update	"force_update"

#undef WOSH_BUILDINGOBJECT
#define WOSH_BUILDINGOBJECT(CLASSNAME)	\
		WOSH_SERIALIZABLE(CLASSNAME)	\


class BuildingObject :		public Object,
							public virtual IPropertiesProviderListener,
							public virtual IBusListener,
							protected MethodRunner
 {
	WOSH_SERIALIZABLE(wosh::building::BuildingObject)
	//BIG BUG about clone(), is the bad solution:? WOSH_SERIALIZABLE_ABSTRACT(wosh::building::BuildingObject)

	typedef MapT<URI, InterfacesProvider*> tURIInterfacesProviderMap;


	public:
		/**
		 * @brief  Empty constructor.
		 */
		BuildingObject();
		/**
		 * @brief  Copy constructor.
		 * @param m [in] the source object to be copied
		 */
		BuildingObject( const BuildingObject& m );
		/**
		 * @brief  Empty destructor.
		 */
		virtual ~BuildingObject();


/** @name Getters
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief  Get the name (string) of the parent. Empty when unset.
		 * @return constant STL string reference (to internal field)
		 */
		const std::string& getParentName() const				{ return this->parent; }

		bool isAlwaysRaisingEvents() const						{ return this->raiseAlwaysEvents; }

		/**
		 * @brief  Get the Interface list, object may implement (support) different interfaces.
		 * @return (constant) Interface list reference
		 */
		const InterfacesProvider& getInterfaces() const			{ return this->Interfaces; }
		/**
		 * @brief  Get the Interface list, object may implement (support) different interfaces.
		 * @return (editable) Interface list reference
		 */
		InterfacesProvider& getInterfaces() 					{ return this->Interfaces; }

		/**
		 * @brief  Get the Properties of the object
		 * @return (constant) PropertiesProvider reference
		 */
		const PropertiesProvider& getProperties() const			{ return this->Properties; }
		/**
		 * @brief  Get the Properties of the object
		 * @return (editable) PropertiesProvider reference
		 */
		PropertiesProvider& getProperties() 					{ return this->Properties; }

		/**
		 * @brief  Get the Geometry of the object
		 * @return (constant) BuildingGeometry reference
		 */
		const BuildingGeometry& getGeometry() const				{ return this->Geometry; }
		/**
		 * @brief  Get the Geometry of the object
		 * @return (editable) BuildingGeometry reference
		 */
		BuildingGeometry& getGeometry() 						{ return this->Geometry; }

		/**
		 * @brief  Evaluate if object is a child object. 
		 * @param [in] object_uri the URI of the child object to be added
		 * @return true if object is a child, false else
		 */
		virtual bool isChild( const URI& object_uri ) const;


		virtual bool isChildA( const URI& object_uri, const std::string& interface_name ) const;

		/**
		 * @brief  Get the number of child objects. 
		 * @return number of registered child objects
		 */
		virtual int countChildren() const							{ return this->children.size(); }

		/**
		 * @brief  Get name of first child object which support requested interface.
		 * @param [in] type the interface name to search for
		 * @return name of the child object
		 */
		std::string getChildByInterface( const std::string& type ) const;

		/**
		 * @brief  Get names of child objects which support requested interface.
		 * @param [in] type the interface name to search for
		 * @param [out] results the list of children matching requested interface
		 * @return number of child object (same as results.size())
		 */
		int getChildrenByInterface( const std::string& type, std::vector<std::string>& results ) const;

		/**
		 * @brief  Get names of child objects.
		 * @param [out] results the list of children
		 * @return number of child object (same as results.size())
		 */
		int getChildren( std::vector<std::string>& results ) const;

		tURIInterfacesProviderMap& getChildren()				{ return this->children; }
		const tURIInterfacesProviderMap& getChildren() const	{ return this->children; }

		static DataFieldCollector<BuildingObject>* getDataFields();

//@}
/** @name Setters
 * @{
 ******************************************************************************/
	public:

		virtual void setName( const std::string& value );
		virtual void setName( const std::string& basename, long id );

		virtual void setPermission( const Permission& value );


		/**
		 * @brief  Set the name (string) of the parent. Empty when unset.
		 * @param [in] value the name of the parent object to be set (copied)
		 */
		void setParentBObj( const URI& value );

		/**
		 * @brief  Register a child object. 
		 * @param [in] object_uri the URI of the child object to be added
		 * @param [in] interfaces the interfaces implemented by the child, it will be owned by the object!
		 * @return WRET_ERR_PARAM if object is not a child, WRET_OK else.
		 */
		virtual WRESULT setChild( const std::string& object_uri, InterfacesProvider* interfaces );

		/**
		 * @brief  Remove (unregister) a child object. Will only remove the reference (not the object's instance).
		 * @param [in] object_uri the URI of the child object to be removed
		 * @return WRET_ERR_PARAM if object is not a child, WRET_OK else.
		 */
		virtual WRESULT removeChild( const URI& object_uri );

//@}
/** @name IBusListener Interface
 * @{
 ******************************************************************************/
	public:
		virtual void busMessage( const Message& message, const Bus* source );

//@}
/** @name Serialization interface
 * @{
 ******************************************************************************/
	public:
		virtual std::string toString() const;
		virtual bool updateHash( DataHashContext* hash_context ) const;
//@}
/** @name Hosted mehods
 * @{
 ******************************************************************************/
	protected:
		Response* mmDoListChildren( const Message* requestMessage );

		WRESULT mmDoUpdatedChildren( const SecurityToken* security );

//@}
/** @name Internal mehods
 * @{
 ******************************************************************************/
	protected:
		std::string getChildByInterface_( const std::string& type ) const;

		int getChildrenByInterface_( const std::string& type, std::vector<std::string>& results ) const;

		virtual WRESULT updatedChildren_( const URI& object_uri, const SecurityToken* security = NULL );
		virtual WRESULT updatedChildren_( const SecurityToken* security );

		/**
		 * @brief  Create a Message (containing selected object) and post to Building Bus
		 * @param [in] content the content of the message to be sent (instance will be deleted)
		 */
		virtual void raiseEvent( MessageContent* content, const SecurityToken* source_token = NULL );

		/**
		 * @brief  Create a Message (containing selected object) for the selected child.
		 * @param [in] child_name the name of the child object to send the message to
		 * @param [in] content the content of the message to be sent (instance will be deleted)
		 * @param [in] source_token 
		 */
		virtual void controlChild( const std::string& child_name, MessageContent* content, const SecurityToken* source_token );

		/**
		 * @brief  Send a Message to the selected child.
		 * @param [in] child_name the name of the child object to send the message to
		 * @param [in] message the message to be sent (some fields will be updated) (instance will be deleted)
		 */
		virtual void controlChild( const std::string& child_name, Message* message );

		/**
		 * @brief  Create a Message (containing selected object) for the selected children (by interface).
		 * @param [in] child_type the type the interface name to search for
		 * @param [in] content the content of the message to be sent (instance will be copied)
		 * @param [in] source_token 
		 */
		virtual int controlChildren( const std::string& child_type, const MessageContent& content, const SecurityToken* source_token );

		virtual int controlChildren_( const std::string& child_type, const MessageContent& content, const SecurityToken* source_token );


		/**
		 * @brief  Send Messages to the selected children.
		 * @param [in] child_type the type of the child object to send the message to
		 * @param [in] message the message to be sent (some fields will be updated) (instance will be deleted)
		 */
		virtual int controlChildren( const std::string& child_type, const Message& message );

		virtual void busMessageChild( const Message& message ) { (void)message; }

		void initBO();

		virtual void init();

		virtual SecurityToken* signMessage( Message* message, const SecurityToken* source_token = NULL ) const;

//@}
/** @name IPropertiesProviderListener interface
 * @{
 ******************************************************************************/
 	public:
		virtual inline bool readingProperty( Property* , const PropertiesProvider* ) { return true; }
		virtual bool updatingProperty( bool& do_update, const Variant& value_proposed, Property& property_current, const PropertiesProvider* source );
//@}
	protected:
		BusConnector BusBuilding;		///< Building bus connector
		BusConnector BusDevices;		///< Devices bus connector

		std::string parent;				///< name of the parent BuildingObject
		bool raiseAlwaysEvents;			///< raise events even when the confirm current state 

		mutable tURIInterfacesProviderMap children;	///< list of children: {name->supported interfaces}

		MethodsProvider Methods;		///< implemented methods
		PropertiesProvider Properties;	///< hosted properties
		InterfacesProvider Interfaces;	///< supported interfaces (names)
		BuildingGeometry Geometry;		///< geometry of the object

		mutable LogContext Log;			///< my log

		friend class wosh::services::BuildingManagerBundle;


}; // class def

 }; // namespace building
}; // namespace wosh

#endif //__WOSH_Building_BuildingObject_H__
